﻿using HDS.IService.Log;
using HDS.IService.Master;
using HDS.Model;
using HDS.Model.Entity.View;
using HDS.Admin.Api.ViewModels.OrderHotel;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Cors;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using System.Threading.Tasks;
using LinqKit;
using System.Security.Claims;
using System;
using HDS.IService.DistributorApi;

namespace HDS.Admin.Api.Controllers
{
    [Route("order/[action]")]
    [ApiController]
    [EnableCors]
    [Authorize]
    public class OrderHotelController : AdminController
    {
        private readonly ILogger<OrderHotelController> _logger;
        private readonly IHotelService _IHotelService;
        private readonly ISupplierHotelService _ISupplierHotelService;
        private readonly ISupplierApiConfigService _ISupplierApiConfigService;
        private readonly IDistributorService _IDistributorService;
        private readonly IUpdateLogService _IUpdateLogService;
        private readonly IOrderHotelService _IOrderHotelService;
        private readonly IDistributorApiService _IDistributorApiService;

        public OrderHotelController(ILogger<OrderHotelController> logger, IHotelService ihotelService, ISupplierHotelService isupplierHotelService, ISupplierApiConfigService isupplierApiConfigService, IDistributorService idistributorConfigService, IOrderHotelService iorderHotelService, IUpdateLogService iupdateLogService, IDistributorApiService idistributorApiService)
        {
            _logger = logger;
            _IHotelService = ihotelService;
            _ISupplierHotelService = isupplierHotelService;
            _ISupplierApiConfigService = isupplierApiConfigService;
            _IDistributorService = idistributorConfigService;
            _IUpdateLogService = iupdateLogService;
            _IOrderHotelService = iorderHotelService;
            _IDistributorApiService = idistributorApiService;
        }

        public async Task<ResultData<DataPagingModel<VOrderHotel>>> GetList([FromBody] SearchDto searchDto)
        {
            var predicate = PredicateBuilder.New<VOrderHotel>(true);
            var whereSql = "";
            if(!string.IsNullOrEmpty(searchDto.OrderId))
                predicate = predicate.And(e => e.OrderId == searchDto.OrderId);
            if (searchDto.OrderStatus.HasValue)
                predicate = predicate.And(e => e.OrderStatus == searchDto.OrderStatus.Value);

            if (!string.IsNullOrEmpty(searchDto.Distributor))
                predicate = predicate.And(e => e.Distributor == searchDto.Distributor);
            if (!string.IsNullOrEmpty(searchDto.DistributorOrderId))
                predicate = predicate.And(e => e.DistributorOrderId == searchDto.DistributorOrderId);
            if (searchDto.DistributorOrderStatus.HasValue)
                predicate = predicate.And(e => e.DistributorOrderStatus == searchDto.DistributorOrderStatus.Value);

            if (!string.IsNullOrEmpty(searchDto.Supplier))
                predicate = predicate.And(e => e.Supplier == searchDto.Supplier);
            if (!string.IsNullOrEmpty(searchDto.SupplierOrderId))
                predicate = predicate.And(e => e.SupplierOrderId == searchDto.SupplierOrderId);
            if (searchDto.SupplierOrderStatus.HasValue)
                predicate = predicate.And(e => e.SupplierOrderStatus == (int)searchDto.SupplierOrderStatus.Value);

            if (searchDto.HotelId.HasValue)
                predicate = predicate.And(e => e.HotelId == searchDto.HotelId);
            if (!string.IsNullOrEmpty(searchDto.HotelName))
                predicate = predicate.And(e => e.HotelName.Contains(searchDto.HotelName.Trim()));
            if (!string.IsNullOrEmpty(searchDto.CountryName))
                predicate = predicate.And(e => e.HotelCountryName.Contains(searchDto.CountryName.Trim()));
            if (!string.IsNullOrEmpty(searchDto.CityName))
                predicate = predicate.And(e => e.HotelCityName.Contains(searchDto.CityName.Trim()));

            if (searchDto.hasAfterSale.HasValue && searchDto.hasAfterSale.Value)
                whereSql = "order_id IN (SELECT order_id FROM order_aftersale)";

            switch (searchDto.DateType)
            {
                case 1:
                    if(searchDto.StartDate.HasValue)
                        predicate = predicate.And(e => e.CreatedTime >= searchDto.StartDate.Value);
                    if(searchDto.EndDate.HasValue)
                        predicate = predicate.And(e => e.CreatedTime <= searchDto.EndDate.Value.AddDays(1).AddSeconds(-1));
                    break;
                case 2:
                    if (searchDto.StartDate.HasValue)
                        predicate = predicate.And(e => e.UpdatedTime >= searchDto.StartDate.Value);
                    if (searchDto.EndDate.HasValue)
                        predicate = predicate.And(e => e.UpdatedTime <= searchDto.EndDate.Value.AddDays(1).AddSeconds(-1));
                    break;
            }

            switch (searchDto.DateType1)
            {
                case 1:
                    if (searchDto.StartDate1.HasValue)
                        predicate = predicate.And(e => e.Checkin >= searchDto.StartDate1.Value);
                    if (searchDto.EndDate1.HasValue)
                        predicate = predicate.And(e => e.Checkin <= searchDto.EndDate1.Value.AddDays(1).AddSeconds(-1));
                    break;
                case 2:
                    if (searchDto.StartDate1.HasValue)
                        predicate = predicate.And(e => e.Checkout >= searchDto.StartDate1.Value);
                    if (searchDto.EndDate1.HasValue)
                        predicate = predicate.And(e => e.Checkout <= searchDto.EndDate1.Value.AddDays(1).AddSeconds(-1));
                    break;
            }

            switch (searchDto.DateType2)
            {
                case 1:
                    if (searchDto.StartDate2.HasValue)
                        predicate = predicate.And(e => e.FreeCancelTime >= searchDto.StartDate2.Value);
                    if (searchDto.EndDate2.HasValue)
                        predicate = predicate.And(e => e.FreeCancelTime <= searchDto.EndDate2.Value.AddDays(1).AddSeconds(-1));
                    break;
                case 2:
                    if (searchDto.StartDate2.HasValue)
                        predicate = predicate.And(e => e.SupplierFreeCancelTime >= searchDto.StartDate2.Value);
                    if (searchDto.EndDate2.HasValue)
                        predicate = predicate.And(e => e.SupplierFreeCancelTime <= searchDto.EndDate2.Value.AddDays(1).AddSeconds(-1));
                    break;
            }

            var dataPaging = await _IOrderHotelService.GetDistributorOrderList(searchDto.PageIndex, searchDto.PageSize, predicate, whereSql);
            return new ResultData<DataPagingModel<VOrderHotel>> { Success = true, Data = dataPaging };
        }

        public async Task<object> GetDetail(string orderId)
        {
            var orderHotelDistributor = await _IOrderHotelService.GetDistributorOrder(orderId);
            var orderSupplierList = await _IOrderHotelService.GetSupplierOrderList(orderId);
            var hotelInfo = await _IHotelService.GetHotel(orderHotelDistributor.HotelId);

            return new { Detail = orderHotelDistributor, SupplierList = orderSupplierList, HotelInfo = hotelInfo };
        }

        public async Task<ResultData<int>> UpdateOrderStatus([FromBody] UpdateOrderStatusDto orderStatusDto)
        {
            var sucess = await _IOrderHotelService.UpdateOrderStatus(orderStatusDto.OrderId, orderStatusDto.OrderStatus, this.UserId, this.UserName, orderStatusDto.LogText);

            return new ResultData<int> { Success = sucess, Data = 0, Message = sucess ? "" : "Update failed" };
        }

        public async Task<ResultData<int>> UpdateHotelConfirmNo([FromBody] UpdateHotelConfirmNoDto confirmNoDto)
        {
            var sucess = await _IOrderHotelService.UpdateHotelConfirmNo(confirmNoDto.OrderId, confirmNoDto.HotelConfirmNo, this.UserId, this.UserName);

            return new ResultData<int> { Success = sucess, Data = 0, Message = sucess ? "" : "Update failed" };
        }

        public async Task<ResultData<string>> PushConfirmRoom(string orderId)
        {
            var orderInfo = await _IOrderHotelService.GetDistributorOrder(orderId);
            if (orderInfo == null)
                throw new NullReferenceException();

            await _IDistributorApiService.InitConfig(orderInfo.Distributor);
            return await _IDistributorApiService.PushConfirmRoom(orderInfo.DistributorOrderId, orderInfo.OrderId, this.UserId, this.UserName);
        }

        public async Task<ResultData<string>> PushHotelConfirmNo(string orderId)
        {
            var orderInfo = await _IOrderHotelService.GetDistributorOrder(orderId);
            if (orderInfo == null || string.IsNullOrEmpty(orderInfo.HotelConfirmNo))
                throw new NullReferenceException();

            await _IDistributorApiService.InitConfig(orderInfo.Distributor);
            return await _IDistributorApiService.PushHotelConfirmNo(orderInfo.DistributorOrderId, orderInfo.OrderId, orderInfo.HotelConfirmNo, this.UserId, this.UserName);
        }
    }
}
